home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / etc / fmt.c < prev    next >
C/C++ Source or Header  |  1992-09-18  |  34KB  |  1,189 lines

  1. /* 
  2.  * fmt.c --
  3.  *
  4.  *    Routines for converting between different formats of data.
  5.  *    A data format includes such things as byte-order and 
  6.  *    alignment. 
  7.  *
  8.  * Copyright 1989 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/fmt.c,v 1.9 92/09/18 09:56:55 mgbaker Exp $ SPRITE (Berkeley)";
  20. #endif /* not lint */
  21. /*LINTLIBRARY*/
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <sys.h>
  29. #include "fmt.h"
  30.  
  31. /*
  32.  * Two supported byte-orders.
  33.  */
  34. #define BIG_ENDIAN 0
  35. #define LITTLE_ENDIAN 1
  36.  
  37. /*
  38.  * Structure for each format. Right now formats only include alignment
  39.  * and byte-order. The alignment fields for bytes, halfwords, words,
  40.  * and doublewords are used to align these data types such that their
  41.  * addresses are a multiple of the alignment.  For example, an alignment
  42.  * of 4 indicates that the address of the data must be a multiple of
  43.  * 4. The alignments for structures and unions are used in the same
  44.  * way, except that they represent the minimum alignment. If the
  45.  * structure or union contains a more restrictive data type the more
  46.  * restrictive alignment is used.
  47.  * 
  48.  * There are two supported byte-orders: little-endian and big-endian.
  49.  * If we view a word as an array of 4 bytes, then byte 0 is the most
  50.  * significant byte of the word if a machine is big-endian and the
  51.  * least significant if the machine is little endian.
  52.  */
  53.  
  54. typedef struct {
  55.     int        bAlign;            /* Byte alignment */
  56.     int        hAlign;            /* Halfword alignment */
  57.     int        wAlign;            /* Word alignment */
  58.     int        dAlign;            /* Doubleword alignment */
  59.     int        structMinAlign;        /* Minimum alignment of structures */
  60.     int        unionMinAlign;        /* Minimum alignment of unions */
  61.     int        byteOrder;        /* Byte order. */
  62. } FormatInfo;
  63.  
  64. /*
  65.  * Byte-order and alignment information for each type.
  66.  */
  67. static FormatInfo formatInfo[] = {
  68.     {1,    2, 2, 2, 2, 2, BIG_ENDIAN},           /* 68K */
  69.     {1, 2, 4, 4, 1, 1, LITTLE_ENDIAN},        /* VAX */
  70.     {1, 2, 4, 8, 4, 4, LITTLE_ENDIAN},       /* SPUR */
  71.     {1, 2, 4, 8, 1, 1, LITTLE_ENDIAN},       /* MIPS */
  72.     {1, 2, 4, 8, 1, 1, BIG_ENDIAN},        /* SPARC */
  73.     {1, 2, 2, 2, 1, 1, LITTLE_ENDIAN}        /* Symmetry */
  74. };
  75.  
  76. /*
  77.  * Number of different formats.
  78.  */
  79. static int formatCount = sizeof(formatInfo) / sizeof(FormatInfo);
  80.  
  81. /*
  82.  * Structure to maintain state of current conversion.
  83.  */
  84. typedef struct {
  85.     char        *contPtr;    /* Ptr to position in content string */
  86.     char        *inEndPtr;    /* Ptr to last byte in input buffer */
  87.     char        *inPtr;        /* Ptr to position in input buffer */
  88.     char        *inStartPtr;    /* Starting input pointer. */
  89.     char        *outEndPtr;    /* Ptr to last byte in output buffer */
  90.     char        *outPtr;    /* Ptr to position in output buffer */
  91.     char        *outStartPtr;    /* Starting output pointer. */
  92.     FormatInfo        *inInfoPtr;    /* Ptr to format info for in format */
  93.     FormatInfo        *outInfoPtr;    /* Ptr to format info for out format */
  94. } State;
  95.  
  96. /*
  97.  * Used to convert Swap_Buffer constants to Fmt constants.
  98.  */
  99.  
  100. static int compat[3] = { 1, 4, 3};
  101.  
  102. /*
  103.  * Forward declaration of procedures.
  104.  */
  105. static int    ConvertSequence _ARGS_((Boolean doCopy, int unionIndex,
  106.                     int openChar, State *statePtr));
  107. static int    ConvertStruct _ARGS_((Boolean doCopy, Boolean doingUnion,
  108.                       State *statePtr, int *repCountPtr));
  109. static int    ConvertUnion _ARGS_((Boolean doCopy, Boolean doingUnion,
  110.                      State *statePtr, int *repCountPtr));
  111. static int    ConvertByte _ARGS_((Boolean doCopy, int repCount,
  112.                     State *statePtr));
  113. static int    ConvertHalfWord _ARGS_((Boolean doCopy, int repCount,
  114.                     State *statePtr));
  115. static int    ConvertWord _ARGS_((Boolean doCopy, int repCount,
  116.                     State *statePtr));
  117. static int    ConvertDoubleWord _ARGS_((Boolean doCopy, int repCount,
  118.                       State *statePtr));
  119. static int    CalcComplexAlign _ARGS_((State *statePtr, char **contPtrPtr,
  120.                      int *repCountPtr, int *inAlignPtr,
  121.                      int *outAlignPtr));
  122.  
  123. /*
  124.  * AlignPointer --
  125.  *
  126.  * Macro to increment a pointer to the given alignment. 
  127.  * The offset is the address of the start of the buffer, since it may
  128.  * not be aligned.  To align a pointer we add in the alignment minus one,
  129.  * then subtract the original alignment (low bits of the offset). 
  130.  * The address is then rounded to the alignment by anding with the inverse
  131.  * of the alignment minus one.  The original alignment is then added back in.
  132.  */
  133.  
  134. #define AlignPointer(align, offset, ptr) { \
  135.     (ptr) = (char *) (( \
  136.     (((int)(ptr)) + (align) - 1 - (((int) offset) & ((align)-1))) \
  137.     & ~((align)-1)) \
  138.     + (((int)offset) & ((align)-1))); \
  139. }
  140.  
  141. /*
  142.  * Return the maximum of two numbers.
  143.  */
  144. #define MAX(a,b) ((a) > (b)) ? (a) : (b)
  145.  
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * Fmt_Convert --
  150.  *
  151.  *    Convert data from one format to another.
  152.  *    See the man page for more details.
  153.  *
  154.  * Results:
  155.  *    Data is read from the input buffer using the input format
  156.  *    and written to the output buffer using the output format.
  157.  *    *inSizePtr contains the actual number of input bytes used
  158.  *    and *outSizePtr contains the actual number of output bytes used.
  159.  *
  160.  *    Returns:
  161.  *    FMT_OK            -- conversion successful.
  162.  *    FMT_CONTENT_ERROR     -- error in content string
  163.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  164.  *                   indicated by content string
  165.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  166.  *    FMT_ILLEGAL_FORMAT    -- one of the formats is bad
  167.  *
  168.  * Side effects:
  169.  *    None.
  170.  *
  171.  *----------------------------------------------------------------------
  172.  */
  173.  
  174. int
  175. Fmt_Convert(contents, inFormat, inSizePtr, inBuf, outFormat, outSizePtr, outBuf)
  176.     char        *contents;    /* String describing contents of 
  177.                      * buffers. */
  178.     Fmt_Format        inFormat;    /* Data format of input buffer */
  179.     int            *inSizePtr;    /* Ptr to size of input buffer */
  180.     char        *inBuf;        /* Input buffer */
  181.     Fmt_Format        outFormat;    /* Data format of output buffer */
  182.     int            *outSizePtr;    /* Ptr to size of output buffer */
  183.     char        *outBuf;    /* Output buffer */
  184. {
  185.  
  186.     State    state;
  187.     int        status;
  188.  
  189.     if ((inFormat & 0x1000) != 0) {
  190.     inFormat &= ~0x1000;
  191.     } else {
  192.     inFormat = compat[inFormat];
  193.     }
  194.     if ((outFormat & 0x1000) != 0) {
  195.     outFormat &= ~0x1000;
  196.     } else {
  197.     outFormat = compat[outFormat];
  198.     }
  199.  
  200.     if (inFormat < 1 || inFormat > formatCount) {
  201.     return FMT_ILLEGAL_FORMAT;
  202.     } 
  203.     if (outFormat < 1 || outFormat > formatCount) {
  204.     return FMT_ILLEGAL_FORMAT;
  205.     } 
  206.     state.contPtr = contents;
  207.     state.inEndPtr = inBuf + *inSizePtr;
  208.     state.inPtr = inBuf;
  209.     state.inStartPtr = inBuf;
  210.     state.outEndPtr = outBuf + *outSizePtr;
  211.     state.outPtr = outBuf;
  212.     state.outStartPtr = outBuf;
  213.     state.inInfoPtr = &(formatInfo[inFormat-1]);
  214.     state.outInfoPtr = &(formatInfo[outFormat-1]);
  215.  
  216.     status = ConvertSequence(TRUE, -1, '\0', &state);
  217.  
  218.     *inSizePtr = (int) (state.inPtr - inBuf);
  219.     *outSizePtr = (int) (state.outPtr - outBuf);
  220.  
  221.     return status;
  222. }
  223.  
  224. /*
  225.  *----------------------------------------------------------------------
  226.  *
  227.  * Fmt_Size --
  228.  *    Compute the size of the data after conversion.
  229.  *    See the man page for more details.
  230.  *
  231.  * Results:
  232.  *    Data is read from the input buffer using the input format
  233.  *    and written to the output buffer using the output format.
  234.  *    *inSizePtr contains the actual number of input bytes used.
  235.  *    *outSizePtr contains the size of the input data after conversion.
  236.  *
  237.  *    Returns:
  238.  *    FMT_OK            -- size calculation successful.
  239.  *    FMT_CONTENT_ERROR     -- error in content string
  240.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  241.  *                   indicated by content string
  242.  *    FMT_ILLEGAL_FORMAT    -- one of the formats is bad
  243.  *
  244.  * Side effects:
  245.  *    None.
  246.  *
  247.  *----------------------------------------------------------------------
  248.  */
  249.  
  250. int
  251. Fmt_Size(contents, inFormat, inSizePtr, outFormat, outSizePtr)
  252.     char        *contents;    /* String describing contents of 
  253.                      * buffers. */
  254.     Fmt_Format        inFormat;    /* Data format of input buffer */
  255.     int            *inSizePtr;    /* Ptr to size of input buffer */
  256.     Fmt_Format        outFormat;    /* Data format of output buffer */
  257.     int            *outSizePtr;    /* Ptr to size of output buffer */
  258. {
  259.  
  260.     State    state;
  261.     int        status;
  262.  
  263.     if ((inFormat & 0x1000) != 0) {
  264.     inFormat &= ~0x1000;
  265.     } else {
  266.     inFormat = compat[inFormat];
  267.     }
  268.     if ((outFormat & 0x1000) != 0) {
  269.     outFormat &= ~0x1000;
  270.     } else {
  271.     outFormat = compat[outFormat];
  272.     }
  273.  
  274.     if (inFormat < 1 || inFormat > formatCount) {
  275.     return FMT_ILLEGAL_FORMAT;
  276.     } 
  277.     if (outFormat < 1 || outFormat > formatCount) {
  278.     return FMT_ILLEGAL_FORMAT;
  279.     } 
  280.     state.contPtr = contents;
  281.     state.inEndPtr = (char *) *inSizePtr;
  282.     state.inPtr = NULL;
  283.     state.inStartPtr = NULL;
  284.     state.outEndPtr = NULL;
  285.     state.outPtr = NULL;
  286.     state.outStartPtr = NULL;
  287.     state.inInfoPtr = &(formatInfo[inFormat-1]);
  288.     state.outInfoPtr = &(formatInfo[outFormat-1]);
  289.  
  290.     status = ConvertSequence(FALSE, -1, '\0', &state);
  291.  
  292.     *inSizePtr = (int) (state.inPtr);
  293.     *outSizePtr = (int) (state.outPtr);
  294.  
  295.     return status;
  296. }
  297.  
  298. /*
  299.  *----------------------------------------------------------------------
  300.  *
  301.  * ConvertSequence --
  302.  *
  303.  *    The conversion process is broken up in a hierarchical manner.
  304.  *    At the leaves are the conversions of bytes, halfwords, words and 
  305.  *    doublewords. Structures and unions are converted by converting
  306.  *    their components. These may be leaves, or they may be nested
  307.  *    structures and unions. Sequences are collections of conversions
  308.  *    at the same nesting level. The initial content string represents
  309.  *    a sequence of conversions, as do the fields of a structure.
  310.  *    The conversion of sequences requires no special alignment like
  311.  *    the other types of conversion.
  312.  *
  313.  *    The doCopy and unionIndex parameters can be used to control the
  314.  *    conversion. If doCopy is FALSE then the output buffer is not
  315.  *    modified. If unionIndex is >= 0, then only one element of the
  316.  *    sequence will be copied into the output buffer (if doCopy is TRUE).
  317.  *    If unionIndex < 0 then the sequence is not the components of a
  318.  *    union so they are all copied (if doCopy is TRUE).  If we are
  319.  *    processing a union the pointers to the input and output buffers
  320.  *    will be adjusted as if the largest element in the sequence had been
  321.  *    copied. For example, the union "(0bw)" should have the byte copied,
  322.  *    but the size of the union is 4 bytes. Keeping track of the largest
  323.  *    component allows the pointers to be advanced to the end of the
  324.  *    union.
  325.  *
  326.  * Results:
  327.  *    The state structure is modified to reflect the current state of
  328.  *    the conversion. Data may be copied from the input buffer to
  329.  *    the output buffer.
  330.  *
  331.  *    Returns:
  332.  *    FMT_OK            -- conversion successful.
  333.  *    FMT_CONTENT_ERROR     -- error in content string
  334.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  335.  *                   indicated by content string
  336.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  337.  *
  338.  * Side effects:
  339.  *    None.
  340.  *
  341.  *----------------------------------------------------------------------
  342.  */
  343.  
  344. static int
  345. ConvertSequence(doCopy, unionIndex, openChar, statePtr)
  346.     Boolean        doCopy;        /* FALSE => don't modify the
  347.                      * output buffer. */
  348.     int            unionIndex;    /* If >= 0 then we are doing a union
  349.                      * so only copy this element and set
  350.                      * pointers to max of elements. */
  351.     char        openChar;    /* The character that started the 
  352.                      * sequence. */
  353.     register State    *statePtr;    /* Current state of conversion */
  354. {
  355.     register char     *contPtr;
  356.     int            status;
  357.     int            repCount;
  358.     char        *afterPtr;
  359.     int            curIndex;
  360.     char        *maxInPtr = (char *)NIL;
  361.     char        *maxOutPtr = (char *)NIL;
  362.     Boolean        doSubCopy;
  363.     char        *startInPtr = (char *)NIL;
  364.     char         *startOutPtr = (char *)NIL;
  365.  
  366.     status = FMT_OK;
  367.     curIndex = 0;
  368.     /*
  369.      * If we are doing a union keep track of where we started and the
  370.      * maximum  pointer values.
  371.      */
  372.     if (unionIndex >= 0) {
  373.     maxInPtr = statePtr->inPtr;
  374.     startInPtr = statePtr->inPtr;
  375.     maxOutPtr = statePtr->outPtr;
  376.     startOutPtr = statePtr->outPtr;
  377.     }
  378.     contPtr = statePtr->contPtr;
  379.     while (*contPtr != '\0') {
  380.     doSubCopy = doCopy && ((unionIndex < 0) || (unionIndex == curIndex));
  381.     switch (*contPtr) {
  382.         case '{' :
  383.         status = ConvertStruct(doSubCopy, unionIndex >= 0,  
  384.                 statePtr, &repCount);
  385.         break;
  386.         case '(' :
  387.         status = ConvertUnion(doSubCopy, unionIndex >= 0,  
  388.                 statePtr, &repCount);
  389.         break;
  390.         case '}' :
  391.         if (openChar != '{') {
  392.             return FMT_CONTENT_ERROR;
  393.         } else {
  394.             statePtr->contPtr = contPtr+1;
  395.             goto exit;
  396.         }
  397.         break;
  398.         case ')' :
  399.         if (openChar != '(') {
  400.             return FMT_CONTENT_ERROR;
  401.         } else {
  402.             statePtr->contPtr = contPtr+1;
  403.             goto exit;
  404.         }
  405.         break;
  406.         default : 
  407.         repCount = 1;
  408.         contPtr++;
  409.         /*
  410.          * Suck up strings of the same character. If we are doing
  411.          * a union we can't do this because they represent different
  412.          * components, not repeated data types within the same
  413.          * component. 
  414.          */
  415.         if (unionIndex < 0) {
  416.             while (*contPtr == *(contPtr-1)) {
  417.             contPtr++;
  418.             repCount++;
  419.             }
  420.         }
  421.         /*
  422.          * Get the repeat count if there is one.
  423.          */
  424.         if ((*contPtr >= '0') && (*contPtr <= '9')) {
  425.             repCount += strtoul(contPtr, &afterPtr, 10) - 1;
  426.             if (contPtr == afterPtr) {
  427.             return FMT_CONTENT_ERROR;
  428.             }
  429.         } else if (*contPtr == '*') {
  430.             repCount = -1;
  431.             afterPtr = contPtr + 1;
  432.         } else {
  433.             afterPtr = contPtr;
  434.         }
  435.         contPtr--;
  436.         if (repCount != 0) {
  437.             switch(*contPtr) {
  438.             case 'b' :
  439.                 status = ConvertByte(doSubCopy, 
  440.                         repCount, statePtr);
  441.                 break;
  442.             case 'h' :
  443.                 status = ConvertHalfWord(doSubCopy,  
  444.                         repCount, statePtr);
  445.                 break;
  446.             case 'w' :
  447.                 status = ConvertWord(doSubCopy, 
  448.                         repCount, statePtr);
  449.                 break;
  450.             case 'd' :
  451.                 status = ConvertDoubleWord(doSubCopy, 
  452.                         repCount, statePtr);
  453.                 break;
  454.             default :
  455.                 return FMT_CONTENT_ERROR;
  456.                 break;
  457.             }
  458.         }
  459.         contPtr = statePtr->contPtr = afterPtr;
  460.     }
  461.     if (status) {
  462.         return status;
  463.     }
  464.     curIndex += 1;
  465.     contPtr = statePtr->contPtr;
  466.     /*
  467.      * Save the max and reset the buffer pointers.
  468.      */
  469.     if (unionIndex >= 0) {
  470.         maxInPtr = MAX(maxInPtr, statePtr->inPtr);
  471.         maxOutPtr = MAX(maxOutPtr, statePtr->outPtr);
  472.         statePtr->inPtr = startInPtr;
  473.         statePtr->outPtr = startOutPtr;
  474.     }
  475.     }
  476. exit:
  477.     if (unionIndex >= 0) {
  478.     statePtr->inPtr = maxInPtr;
  479.     statePtr->outPtr = maxOutPtr;
  480.     }
  481.     return status;
  482. }
  483.  
  484.  
  485. /*
  486.  *----------------------------------------------------------------------
  487.  *
  488.  * ConvertStruct --
  489.  *
  490.  *    Process a structure conversion. Unlike simple data types, we don't
  491.  *    recognize strings of repeated structures. If the same structure is
  492.  *    repeated twice then we parse it twice. If a structure definition
  493.  *    is followed by a repeat count, then we parse the definition multiple
  494.  *    times also. It's too hard to do it differently. Also, since structure
  495.  *    definitions are variable length the repeat count is not passed in
  496.  *    by the calling procedure.  We pass it out instead.
  497.  *    
  498.  *    The doingUnion flag indicates that the structure is a member of a
  499.  *    union. If it is followed by a repeat count then only convert one
  500.  *    of them.
  501.  *
  502.  * Results:
  503.  *    Contents of the state record are modified to represent the
  504.  *    current state of the conversion. The content pointer is advanced
  505.  *    over the description of the structure and its rep count. 
  506.  *    inPtr and outPtr are advanced.
  507.  *    
  508.  *    Returns:
  509.  *    FMT_OK            -- conversion successful.
  510.  *    FMT_CONTENT_ERROR     -- error in content string
  511.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  512.  *                   indicated by content string
  513.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  514.  *
  515.  * Side effects:
  516.  *    None.
  517.  *
  518.  *----------------------------------------------------------------------
  519.  */
  520.  
  521. static int
  522. ConvertStruct(doCopy, doingUnion, statePtr, repCountPtr)
  523.     Boolean        doCopy;     /* FALSE => don't modify output
  524.                      * buffer. */
  525.     Boolean        doingUnion;    /* TRUE => ignore rep count and only
  526.                      * convert one. */
  527.     register State    *statePtr;    /* Current state of conversion */
  528.     int            *repCountPtr;    /* Number of repetitions. */
  529. {
  530.  
  531.     char        *contPtr;
  532.     char        *afterPtr;
  533.     int            status;
  534.     int            repCount;
  535.     register int    count;
  536.     int            inAlign;
  537.     int            outAlign;
  538.  
  539.     afterPtr = statePtr->contPtr;
  540.     status = CalcComplexAlign(statePtr, &afterPtr, &repCount, &inAlign, 
  541.             &outAlign);
  542.     if (status) {
  543.     return status;
  544.     }
  545.     if (doingUnion) {
  546.     count = 1;
  547.     } else {
  548.     count = repCount;
  549.     }
  550.     contPtr = statePtr->contPtr + 1;
  551.     for (; count != 0; count--) {
  552.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  553.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  554.     /*
  555.      * If the structure is followed by a '*' and we are at the end of
  556.      * the input buffer then bail out.
  557.      */
  558.     if ((count < 0) && (statePtr->inPtr == statePtr->inEndPtr)) {
  559.         break;
  560.     }
  561.     statePtr->contPtr = contPtr;
  562.     status = ConvertSequence(doCopy, -1, '{', statePtr);
  563.     if (status) {
  564.         return status;
  565.     }
  566.     }
  567.     /*
  568.      * Structure size is always a multiple of the alignment.
  569.      */
  570.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  571.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  572.     statePtr->contPtr = afterPtr;
  573.     *repCountPtr = repCount;
  574.     return status;
  575.  
  576. }
  577.  
  578.  
  579. /*
  580.  *----------------------------------------------------------------------
  581.  *
  582.  * ConvertUnion --
  583.  *
  584.  *    Process a union conversion. The comments for ConvertStruct apply.
  585.  *    The opening parenthesis of a union definition is followed by the
  586.  *    discriminator (index of the element to be copied). This discriminator
  587.  *    is passed to ConvertSequence so only that element is copied.
  588.  *
  589.  * Results:
  590.  *    Contents of the state record are modified to represent the
  591.  *    current state of the conversion. The content pointer is advanced
  592.  *    over the description of the union and its rep count. 
  593.  *    inPtr and outPtr are advanced.
  594.  *
  595.  *    Returns:
  596.  *    FMT_OK            -- conversion successful.
  597.  *    FMT_CONTENT_ERROR     -- error in content string
  598.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  599.  *                   indicated by content string
  600.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  601.  *
  602.  * Side effects:
  603.  *    None.
  604.  *
  605.  *----------------------------------------------------------------------
  606.  */
  607.  
  608. static int
  609. ConvertUnion(doCopy, doingUnion, statePtr, repCountPtr)
  610.     Boolean        doCopy;     /* FALSE => don't modify output
  611.                      * buffer. */
  612.     Boolean        doingUnion;    /* TRUE => ignore rep count and only
  613.                      * convert one. */
  614.     register State    *statePtr;    /* Current state of conversion */
  615.     int            *repCountPtr;    /* Number of repetitions. */
  616. {
  617.  
  618.     char        *contPtr;
  619.     char        *afterPtr;
  620.     int            status;
  621.     int            repCount;
  622.     register int    count;
  623.     char        *tempPtr;
  624.     int            index;
  625.     int            inAlign;
  626.     int            outAlign;
  627.  
  628.     afterPtr = statePtr->contPtr;
  629.     status = CalcComplexAlign(statePtr, &afterPtr, &repCount, &inAlign, 
  630.             &outAlign);
  631.     if (status) {
  632.     return status;
  633.     }
  634.     if (doingUnion) {
  635.     count = 1;
  636.     } else {
  637.     count = repCount;
  638.     }
  639.     contPtr = statePtr->contPtr + 1;
  640.     /*
  641.      * Get the discriminator.
  642.      */
  643.     if ((*contPtr >= '0') && (*contPtr <= '9')) {
  644.     index = strtoul(contPtr, &tempPtr, 10);
  645.     if (contPtr == tempPtr) {
  646.         return FMT_CONTENT_ERROR;
  647.     }
  648.     } else {
  649.     return FMT_CONTENT_ERROR;
  650.     }
  651.     contPtr = tempPtr;
  652.     for (; count != 0; count--) {
  653.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  654.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  655.     /*
  656.      * If the union is followed by a '*' and we are at the end of
  657.      * the input buffer then bail out.
  658.      */
  659.     if ((count < 0) && (statePtr->inPtr == statePtr->inEndPtr)) {
  660.         break;
  661.     }
  662.     statePtr->contPtr = contPtr;
  663.     status = ConvertSequence(doCopy, index, '(', statePtr);
  664.     if (status) {
  665.         return status;
  666.     }
  667.     }
  668.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  669.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  670.     statePtr->contPtr = afterPtr;
  671.     *repCountPtr = repCount;
  672.     return status;
  673. }
  674.  
  675.  
  676. /*
  677.  *----------------------------------------------------------------------
  678.  *
  679.  * ConvertByte --
  680.  *
  681.  *    If doCopy is TRUE, then copy bytes from the input buffer to the
  682.  *    output buffer. Otherwise just advance the buffer pointers.
  683.  *    If either buffer is too small then return an error. An exception
  684.  *     is made if the pointer to the end of the output buffer is NULL.
  685.  *    This indicates that there isn't an output buffer.
  686.  *
  687.  * Results:
  688.  *    The contents of the state structure are modified to reflect the
  689.  *    current state of the conversion. The input and output pointers
  690.  *    are aligned and advanced repCount bytes.
  691.  *
  692.  *    Returns:
  693.  *    FMT_OK            -- conversion successful.
  694.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  695.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  696.  *
  697.  * Side effects:
  698.  *    None.
  699.  *
  700.  *----------------------------------------------------------------------
  701.  */
  702.  
  703. static int
  704. ConvertByte(doCopy, repCount, statePtr)
  705.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  706.     int            repCount;    /* Number of bytes to copy. */
  707.     State        *statePtr;    /* Current state of conversion. */
  708. {
  709.     register int    i;
  710.     register char    *inPtr;
  711.     register char    *outPtr;
  712.     int            status;
  713.  
  714.     inPtr = statePtr->inPtr;
  715.     outPtr = statePtr->outPtr;
  716.     status = FMT_OK;
  717.  
  718.     AlignPointer(statePtr->inInfoPtr->bAlign, statePtr->inStartPtr, inPtr);
  719.     AlignPointer(statePtr->outInfoPtr->bAlign, statePtr->outStartPtr, outPtr);
  720.  
  721.     if (repCount > 0) {
  722.     if (inPtr + repCount  > statePtr->inEndPtr) {
  723.         status = FMT_INPUT_TOO_SMALL;
  724.         repCount = statePtr->inEndPtr - inPtr;
  725.     }
  726.     } else {
  727.     repCount = statePtr->inEndPtr - inPtr;
  728.     }
  729.     if (statePtr->outEndPtr != NULL && 
  730.     outPtr + repCount > statePtr->outEndPtr) {
  731.     status = FMT_OUTPUT_TOO_SMALL;
  732.     repCount = statePtr->outEndPtr - outPtr;
  733.     }
  734.     if (doCopy) {
  735.     for (i = 0; i < repCount; i++) {
  736.         *outPtr = *inPtr;
  737.         outPtr++;
  738.         inPtr++;
  739.     }
  740.     } else {
  741.     inPtr += repCount;
  742.     outPtr += repCount;
  743.     }
  744.  
  745.     statePtr->inPtr = inPtr;
  746.     statePtr->outPtr = outPtr;
  747.     return status;
  748. }
  749.  
  750.  
  751. /*
  752.  *----------------------------------------------------------------------
  753.  *
  754.  * ConvertHalfWord --
  755.  *
  756.  *    If doCopy is TRUE, then copy halfwords from the input buffer to the
  757.  *    output buffer. Otherwise just advance the buffer pointers.
  758.  *    If either buffer is too small then return an error. An exception
  759.  *     is made if the pointer to the end of the output buffer is NULL.
  760.  *    This indicates that there isn't an output buffer.
  761.  *
  762.  * Results:
  763.  *    The contents of the state structure are modified to reflect the
  764.  *    current state of the conversion. The input and output pointers
  765.  *    are aligned and advanced repCount halfwords.
  766.  *
  767.  *    Returns:
  768.  *    FMT_OK            -- conversion successful.
  769.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  770.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  771.  *
  772.  * Side effects:
  773.  *    None.
  774.  *
  775.  *----------------------------------------------------------------------
  776.  */
  777.  
  778. static int
  779. ConvertHalfWord(doCopy, repCount, statePtr)
  780.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  781.     int            repCount;    /* Number of halfwords to copy. */
  782.     State        *statePtr;    /* Current state of conversion. */
  783. {
  784.     register int    i;
  785.     register char    *inPtr;
  786.     register char    *outPtr;
  787.     int            status;
  788.  
  789.     inPtr = statePtr->inPtr;
  790.     outPtr = statePtr->outPtr;
  791.     status = FMT_OK;
  792.  
  793.  
  794.     AlignPointer(statePtr->inInfoPtr->hAlign, statePtr->inStartPtr, inPtr);
  795.     AlignPointer(statePtr->outInfoPtr->hAlign, statePtr->outStartPtr, outPtr);
  796.  
  797.     if (repCount > 0) {
  798.     if (inPtr + repCount * 2  > statePtr->inEndPtr) {
  799.         status = FMT_INPUT_TOO_SMALL;
  800.         repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 2;
  801.     }
  802.     } else if (repCount < 0) {
  803.     repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 2;
  804.     } else {
  805.     return status;
  806.     }
  807.     if (statePtr->outEndPtr != NULL && 
  808.         outPtr + repCount * 2 > statePtr->outEndPtr) {
  809.     status = FMT_OUTPUT_TOO_SMALL;
  810.     repCount = (((int) statePtr->outEndPtr) - ((int) repCount)) / 2;
  811.     }
  812.     if (doCopy) {
  813.     if (statePtr->inInfoPtr->byteOrder == 
  814.         statePtr->outInfoPtr->byteOrder) { 
  815.  
  816.         for (i = 0; i < repCount; i++) {
  817.         outPtr[0] = inPtr[0];
  818.         outPtr[1] = inPtr[1];
  819.         inPtr += 2;
  820.         outPtr += 2;
  821.         }
  822.     } else {
  823.         for (i = 0; i < repCount; i++) {
  824.         outPtr[0] = inPtr[1];
  825.         outPtr[1] = inPtr[0];
  826.         inPtr += 2;
  827.         outPtr += 2;
  828.         }
  829.     }
  830.     } else {
  831.     inPtr += repCount * 2;
  832.     outPtr += repCount * 2;
  833.     }
  834.     statePtr->inPtr = inPtr;
  835.     statePtr->outPtr = outPtr;
  836.     return status;
  837. }
  838.  
  839. /*
  840.  *----------------------------------------------------------------------
  841.  *
  842.  * ConvertWord --
  843.  *
  844.  *    If doCopy is TRUE, then copy words from the input buffer to the
  845.  *    output buffer. Otherwise just advance the buffer pointers.
  846.  *    If either buffer is too small then return an error. An exception
  847.  *     is made if the pointer to the end of the output buffer is NULL.
  848.  *    This indicates that there isn't an output buffer.
  849.  *
  850.  * Results:
  851.  *    The contents of the state structure are modified to reflect the
  852.  *    current state of the conversion. The input and output pointers
  853.  *    are aligned and advanced repCount words.
  854.  *
  855.  *    Returns:
  856.  *    FMT_OK            -- conversion successful.
  857.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  858.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  859.  *
  860.  * Side effects:
  861.  *    None.
  862.  *
  863.  *----------------------------------------------------------------------
  864.  */
  865.  
  866. static int
  867. ConvertWord(doCopy, repCount, statePtr)
  868.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  869.     int            repCount;    /* Number of words to copy. */
  870.     State        *statePtr;    /* Current state of conversion. */
  871. {
  872.     register int    i;
  873.     register char    *inPtr;
  874.     register char    *outPtr;
  875.     int            status;
  876.  
  877.     inPtr = statePtr->inPtr;
  878.     outPtr = statePtr->outPtr;
  879.     status = FMT_OK;
  880.  
  881.     AlignPointer(statePtr->inInfoPtr->wAlign, statePtr->inStartPtr, inPtr);
  882.     AlignPointer(statePtr->outInfoPtr->wAlign, statePtr->outStartPtr, outPtr);
  883.  
  884.     if (repCount > 0) {
  885.     if (inPtr + repCount * 4 > statePtr->inEndPtr) {
  886.         status = FMT_INPUT_TOO_SMALL;
  887.         repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 4;
  888.     }
  889.     } else if (repCount < 0) {
  890.     repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 4;
  891.     } else {
  892.     return status;
  893.     }
  894.     if (statePtr->outEndPtr != NULL && 
  895.         outPtr + repCount * 4 > statePtr->outEndPtr) {
  896.     status = FMT_OUTPUT_TOO_SMALL;
  897.     repCount = ((int) statePtr->outEndPtr - ((int) outPtr)) / 4;
  898.     }
  899.     if (doCopy) {
  900.     if (statePtr->inInfoPtr->byteOrder == 
  901.         statePtr->outInfoPtr->byteOrder) { 
  902.         for (i = 0; i < repCount; i++) {
  903.         outPtr[0] = inPtr[0];
  904.         outPtr[1] = inPtr[1];
  905.         outPtr[2] = inPtr[2];
  906.         outPtr[3] = inPtr[3];
  907.         inPtr += 4;
  908.         outPtr += 4;
  909.         }
  910.     } else {
  911.         for (i = 0; i < repCount; i++) {
  912.         outPtr[0] = inPtr[3];
  913.         outPtr[1] = inPtr[2];
  914.         outPtr[2] = inPtr[1];
  915.         outPtr[3] = inPtr[0];
  916.         inPtr += 4;
  917.         outPtr += 4;
  918.         }
  919.     }
  920.     } else {
  921.     inPtr += repCount * 4;
  922.     outPtr += repCount * 4;
  923.     }
  924.     statePtr->inPtr = inPtr;
  925.     statePtr->outPtr = outPtr;
  926.     return status;
  927. }
  928.  
  929. /*
  930.  *----------------------------------------------------------------------
  931.  *
  932.  * ConvertDoubleWord --
  933.  *
  934.  *    If doCopy is TRUE, then copy doublewords from the input buffer to
  935.  *    the output buffer. Otherwise just advance the buffer pointers.  If
  936.  *    either buffer is too small then return an error. An exception is
  937.  *    made if the pointer to the end of the output buffer is NULL.  This
  938.  *    indicates that there isn't an output buffer.
  939.  *
  940.  * Results:
  941.  *    The contents of the state structure are modified to reflect the
  942.  *    current state of the conversion. The input and output pointers
  943.  *    are aligned and advanced repCount doublewords.
  944.  *    
  945.  *    Returns:
  946.  *    FMT_OK            -- conversion successful.
  947.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  948.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  949.  *
  950.  * Side effects:
  951.  *    None.
  952.  *
  953.  *----------------------------------------------------------------------
  954.  */
  955.  
  956. static int
  957. ConvertDoubleWord(doCopy, repCount, statePtr)
  958.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  959.     int            repCount;    /* Number of doublewords to copy. */
  960.     State        *statePtr;    /* Current state of conversion. */
  961. {
  962.     register int    i;
  963.     register char    *inPtr;
  964.     register char    *outPtr;
  965.     int            status;
  966.  
  967.     inPtr = statePtr->inPtr;
  968.     outPtr = statePtr->outPtr;
  969.     status = FMT_OK;
  970.  
  971.     AlignPointer(statePtr->inInfoPtr->dAlign, statePtr->inStartPtr, inPtr);
  972.     AlignPointer(statePtr->outInfoPtr->dAlign, statePtr->outStartPtr, outPtr);
  973.  
  974.     if (repCount > 0) {
  975.     if (inPtr + repCount * 8 > statePtr->inEndPtr) {
  976.         status = FMT_INPUT_TOO_SMALL;
  977.         repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 8;
  978.     }
  979.     } else if (repCount < 0) {
  980.     repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 8;
  981.     } else {
  982.     return status;
  983.     }
  984.     if (statePtr->outEndPtr != NULL && 
  985.         outPtr + repCount * 8 > statePtr->outEndPtr) {
  986.     status = FMT_OUTPUT_TOO_SMALL;
  987.     repCount = (((int) statePtr->outEndPtr) - ((int) outPtr)) / 8;
  988.     }
  989.     if (doCopy) {
  990.     if (statePtr->inInfoPtr->byteOrder == 
  991.         statePtr->outInfoPtr->byteOrder) { 
  992.  
  993.         for (i = 0; i < repCount; i++) {
  994.         outPtr[0] = inPtr[0];
  995.         outPtr[1] = inPtr[1];
  996.         outPtr[2] = inPtr[2];
  997.         outPtr[3] = inPtr[3];
  998.         outPtr[4] = inPtr[4];
  999.         outPtr[5] = inPtr[5];
  1000.         outPtr[6] = inPtr[6];
  1001.         outPtr[7] = inPtr[7];
  1002.         inPtr += 8;
  1003.         outPtr += 8;
  1004.         }
  1005.     } else {
  1006.         for (i = 0; i < repCount; i++) {
  1007.         outPtr[0] = inPtr[7];
  1008.         outPtr[1] = inPtr[6];
  1009.         outPtr[2] = inPtr[5];
  1010.         outPtr[3] = inPtr[4];
  1011.         outPtr[4] = inPtr[3];
  1012.         outPtr[5] = inPtr[2];
  1013.         outPtr[6] = inPtr[1];
  1014.         outPtr[7] = inPtr[0];
  1015.         inPtr += 8;
  1016.         outPtr += 8;
  1017.         }
  1018.     }
  1019.     } else {
  1020.     inPtr += repCount * 8;
  1021.     outPtr += repCount * 8;
  1022.     }
  1023.     statePtr->inPtr = inPtr;
  1024.     statePtr->outPtr = outPtr;
  1025.     return status;
  1026. }
  1027.  
  1028. /*
  1029.  *----------------------------------------------------------------------
  1030.  *
  1031.  * CalcComplexAlign --
  1032.  *
  1033.  *    Calculate the alignment of a structure or a union. The alignment
  1034.  *    is the maximum of the alignment specified by the format and the
  1035.  *    alignments of the fields. The repeat count is read and returned
  1036.  *    in *repCountPtr. If the data type is followed by '*' then -1 is
  1037.  *    returned as the repeat count.
  1038.  *
  1039.  * Results:
  1040.  *    *contPtrPtr points to the first character after the data type
  1041.  *    definition and repeat count. *inAlignPtr contains the alignment
  1042.  *    for the in format, and *outAlignPtr contains the alignment for the
  1043.  *    out format. *repCountPtr contains the repeat count.
  1044.  *
  1045.  *    Returns:
  1046.  *    FMT_OK            -- conversion successful.
  1047.  *    FMT_CONTENT_ERROR     -- error in content string
  1048.  *
  1049.  * Side effects:
  1050.  *    None.
  1051.  *
  1052.  *----------------------------------------------------------------------
  1053.  */
  1054.  
  1055. static int
  1056. CalcComplexAlign(statePtr, contPtrPtr, repCountPtr, inAlignPtr, outAlignPtr)
  1057.     State         *statePtr;    /* Current state of conversion. */
  1058.     char        **contPtrPtr;    /* Ptr to ptr to content string */
  1059.     int            *repCountPtr;    /* Ptr to repeat count. */
  1060.     int            *inAlignPtr;    /* Ptr to in alignment. */
  1061.     int            *outAlignPtr;    /* Ptr to out alignment. */
  1062. {
  1063.     int                inAlign = 0; /* dummy initial value */
  1064.     int                outAlign = 0; /* dummy initial value */
  1065.     register char        *contPtr;
  1066.     Boolean            doingUnion = FALSE; /* dummy initial value */
  1067.     char            lastChar;
  1068.     int                status;
  1069.     int                repCount;
  1070.     char            *tempPtr;
  1071.     register FormatInfo        *inInfoPtr;
  1072.     register FormatInfo        *outInfoPtr;
  1073.  
  1074.     status = FMT_OK;
  1075.     contPtr = *contPtrPtr;
  1076.     inInfoPtr = statePtr->inInfoPtr;
  1077.     outInfoPtr = statePtr->outInfoPtr;
  1078.     switch (*contPtr) {
  1079.     case '{' :
  1080.         inAlign = inInfoPtr->structMinAlign;
  1081.         outAlign = outInfoPtr->structMinAlign;
  1082.         doingUnion = FALSE;
  1083.         break;
  1084.     case '(' :
  1085.         inAlign = inInfoPtr->unionMinAlign;
  1086.         outAlign = outInfoPtr->unionMinAlign;
  1087.         doingUnion = TRUE;
  1088.         break;
  1089.     default :
  1090.         panic("Fmt: Internal error: CalcComplexAlign called improperly.\n");
  1091.     }
  1092.     contPtr++;
  1093.     lastChar = '\0';
  1094.     while (*contPtr != '\0') {
  1095.     if (*contPtr == lastChar) {
  1096.         contPtr++;
  1097.         continue;
  1098.     }
  1099.     lastChar = *contPtr;
  1100.     if ((*contPtr >= '0') && (*contPtr <= '9')) {
  1101.         contPtr++;
  1102.         continue;
  1103.     }
  1104.     switch (*contPtr) {
  1105.         case 'b':
  1106.         inAlign = MAX(inAlign, inInfoPtr->bAlign);
  1107.         outAlign = MAX(outAlign, outInfoPtr->bAlign);
  1108.         contPtr++;
  1109.         break;
  1110.         case 'h':
  1111.         inAlign = MAX(inAlign, inInfoPtr->hAlign);
  1112.         outAlign = MAX(outAlign, outInfoPtr->hAlign);
  1113.         contPtr++;
  1114.         break;
  1115.         case 'w':
  1116.         inAlign = MAX(inAlign, inInfoPtr->wAlign);
  1117.         outAlign = MAX(outAlign, outInfoPtr->wAlign);
  1118.         contPtr++;
  1119.         break;
  1120.         case 'd':
  1121.         inAlign = MAX(inAlign, inInfoPtr->dAlign);
  1122.         outAlign = MAX(outAlign, outInfoPtr->dAlign);
  1123.         contPtr++;
  1124.         break;
  1125.         case '(':
  1126.         case '{': {
  1127.         int dummy;
  1128.         int tempInAlign;
  1129.         int tempOutAlign;
  1130.         char *tempContPtr;
  1131.         tempContPtr = contPtr;
  1132.         status = CalcComplexAlign(statePtr, &tempContPtr, &dummy, 
  1133.                 &tempInAlign, &tempOutAlign);
  1134.         if (status) {
  1135.             return status;
  1136.         }
  1137.         inAlign = MAX(inAlign, tempInAlign);
  1138.         outAlign = MAX(outAlign, tempOutAlign);
  1139.         contPtr = tempContPtr;
  1140.         lastChar = '\0';
  1141.         break;
  1142.         }
  1143.         case ')':
  1144.         if (!doingUnion) {
  1145.             return FMT_CONTENT_ERROR;
  1146.         }
  1147.         contPtr++;
  1148.         goto exit;
  1149.         break;
  1150.         case '}':
  1151.         if (doingUnion) {
  1152.             return FMT_CONTENT_ERROR;
  1153.         }
  1154.         contPtr++;
  1155.         goto exit;
  1156.         break;
  1157.         case '*' :
  1158.         contPtr++;
  1159.         break;
  1160.         default :
  1161.         return FMT_CONTENT_ERROR;
  1162.         break;
  1163.     }
  1164.     }
  1165.     return FMT_CONTENT_ERROR;
  1166. exit :
  1167.     /*
  1168.      * Parse the repeat count.
  1169.      */
  1170.     if ((*contPtr >= '0') && (*contPtr <= '9')) {
  1171.     repCount = strtoul(contPtr, &tempPtr, 10);
  1172.     if (contPtr == tempPtr) {
  1173.         return FMT_CONTENT_ERROR;
  1174.     }
  1175.     contPtr = tempPtr;
  1176.     } else if (*contPtr == '*') {
  1177.     repCount = -1;
  1178.     contPtr++;
  1179.     } else {
  1180.     repCount = 1;
  1181.     }
  1182.     *repCountPtr = repCount;
  1183.     *contPtrPtr = contPtr;
  1184.     *inAlignPtr = inAlign;
  1185.     *outAlignPtr = outAlign;
  1186.     return status;
  1187. }
  1188.  
  1189.